#ifndef GPIO_H_
#define GPIO_H_

#include <stdint.h>
#include <sys/mman.h>

typedef uint_fast32_t uint32;
typedef int_fast32_t int32;



namespace IO_access {
    const uint32 BCM2708_PERIPH_BASE = 0x20000000;
    const uint32 GPIO_BASE = (BCM2708_PERIPH_BASE + 0x200000);
    const uint32 BLOCK_SIZE = (4 * 1024);
};



class GPIO {
public:
    enum gpio_names{
        GPIO_04 = 4,
        GPIO_17 = 17,
        GPIO_18 = 18,
        GPIO_21 = 21,
        GPIO_22 = 22,
        GPIO_23 = 23,
        GPIO_24 = 24,
        GPIO_25 = 25
    };

    int do_map();
    volatile uintptr_t *get_addr();
    void config_as_input(gpio_names gpio_name);
    void config_as_output(gpio_names gpio_name);
    void inline set(gpio_names gpio_name) {
        *(addr + 7) = 1 << gpio_name;
    }
    void inline clr(gpio_names gpio_name) {
        *(addr + 10) = 1 << gpio_name;
    }
    void inline read(gpio_names gpio_name) {
        *(addr + 13) &= (1 << gpio_name);
    }


    /* Force singleton access */
    static inline GPIO& getGPIO() {
        static GPIO instance;
        return (instance);
    }


private:
    uint32 addr_p;
    void *mmap_retval;
    volatile uintptr_t *addr;


    /* Private constructor for singleton */
    GPIO(){}

    /* Keep these empty to prevent duplication of this singleton. */
    GPIO(const GPIO& gpio);
    void operator=(const GPIO&);
};


#endif /* GPIO_H_ */
